package xyz.xpman.prisonerfitness.kit;

import android.annotation.SuppressLint;
import android.os.Build;
import android.os.Environment;
import android.util.Log;

import androidx.annotation.RequiresApi;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import xyz.xpman.prisonerfitness.util.MyUuidUtil;

/**
 * 阉割版
 * @author 江理_网猿 (timor)
 * @date 2020/10/10 0010
 */
@SuppressLint("SimpleDateFormat")
public class FormatKit {
    public static final String COMMON = "yyyy-MM-dd_HH-mm-ss";

    private static final String PATTERN_STRING = "\\{([^\\}]+)\\}";

    private static final String ESD = "esd";

    private static final String TIME = "time";
    private static final String FULL_YEAR = "yyyy";
    private static final String YEAR = "yy";
    private static final String MONTH = "MM";
    private static final String DAY = "dd";
    private static final String HOUR = "HH";
    private static final String MINUTE = "mm";
    private static final String SECOND = "ss";
    private static final String TIME_MILL = "SS";
    private static final String NANO_TIME = "NANO_TIME";

    private static final String NEXT_SEQ = "NEXT_SEQ";

    private static final String UUID = "UUID";

    public static final AtomicLong SEQ =new AtomicLong();


    private static final ThreadLocal<Date> DATE_THREAD_LOCAL = new ThreadLocal<>();

    private static final Map<String, Supplier<String>> FORMAT_PATTERN = new HashMap<>();

    private static final Pattern PATTERN = Pattern.compile(PATTERN_STRING, Pattern.CASE_INSENSITIVE);

    static {
        final String[] patternFlag =
                {COMMON, FULL_YEAR, YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, TIME_MILL};
        for (String flag : patternFlag) {
            FORMAT_PATTERN.put(flag, ()-> (new SimpleDateFormat(flag)).format(getCurrentDate()));
        }

        FORMAT_PATTERN.put(UUID, MyUuidUtil::get);
        FORMAT_PATTERN.put(NANO_TIME, ()-> String.valueOf(System.nanoTime()));
        FORMAT_PATTERN.put(TIME, ()-> String.valueOf(System.currentTimeMillis()));
        FORMAT_PATTERN.put(NEXT_SEQ, FormatKit::geNetSeq);


        FORMAT_PATTERN.put(ESD, () ->
                Environment.getExternalStorageDirectory().toString());
    }

    private FormatKit(){}


    public static Date getCurrentDate(){
        Date date = DATE_THREAD_LOCAL.get();
        if(null == date){
            date = new Date();
            DATE_THREAD_LOCAL.set(date);
        }
        return date;
    }



    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


    @RequiresApi(api = Build.VERSION_CODES.N)
    public static String parse(String input) {
        Matcher matcher = PATTERN.matcher(input);
        StringBuffer sb = new StringBuffer();

        while(matcher.find()) {
            matcher.appendReplacement(sb, format(matcher.group(1)));
        }

        matcher.appendTail(sb);
        DATE_THREAD_LOCAL.remove();
        return sb.toString();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    public static String parse(String input, String filename) {
        final Matcher matcher = PATTERN.matcher(input);
        final StringBuffer sb = new StringBuffer();

        while(matcher.find()) {
            final String matchStr = matcher.group(1);

            if (null == matchStr) {
                Log.i("parse", "matchStr = matcher.group(1)  ->  null");
                continue;
            }

            if (matchStr.contains("fileName")) {
                filename = filename.replace("$", "\\$")
                        .replaceAll("[\\\\/:*?\"<>|]", "");
                matcher.appendReplacement(sb, filename);
            } else {
                matcher.appendReplacement(sb, format(matchStr));
            }
        }

        DATE_THREAD_LOCAL.remove();
        matcher.appendTail(sb);
        return sb.toString();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private static String format(String pattern) {
        Supplier<String> supplier = FORMAT_PATTERN.get(pattern);
        if(null != supplier){
            return supplier.get();
        }

        return pattern;
    }


    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


    private static String geNetSeq() {
        return String.valueOf(netSeq());
    }

    private static long netSeq() {
        return SEQ.incrementAndGet();
    }
}
